package com.generator.core;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import com.generator.bean.ControllerProcessBean;
import com.generator.bean.EntityProcessBean;
import com.generator.bean.MapperProcessBean;
import com.generator.bean.MybatisProcessBean;
import com.generator.bean.ServiceProcessBean;
import com.generator.bean.base.GenaratorBaseBean;
import com.generator.bean.common.ClassInfo;
import com.generator.bean.common.Field;
import com.generator.bean.core.GenaratorCtxBean;
import com.generator.config.ContextConfig;
import com.generator.tools.text.StringUtils;
import com.generator.utils.FreemarkerTools;

import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ProcessCoreBiz {
	@Resource
    private FreemarkerTools freemarkerTool;
	@Resource
    private ContextConfig contextConfig;

	public ProcessCoreBiz(ContextConfig contextConfig, FreemarkerTools freemarkerTool) {
		super();
		this.contextConfig = contextConfig;
		this.freemarkerTool = freemarkerTool;
	}

	public void process() {
		String basePackage = contextConfig.getBasePackage();
		String author = contextConfig.getAuthor();
		String driverClassName = contextConfig.getDriverClassName();
		String url = contextConfig.getUrl();
		String userName = contextConfig.getUser();
		String password = contextConfig.getPassword();

		log.info("driverClassName：{}", driverClassName);
		log.info("url:{}", url);
		log.info("userName:{}", userName);
		log.info("password:{}", password);

		log.info("basePackage:{}", basePackage);
		log.info("author:{}", author);
		Connection conn = null;
		// 表查询结果集
		ResultSet tableRS = null;
		try {
			Class.forName(driverClassName);
			conn = DriverManager.getConnection(url, userName, password);
			DatabaseMetaData dbMetaData = conn.getMetaData();
			String catalog = conn.getCatalog(); //catalog 其实也就是数据库名  
			// 获取表的结果集
			tableRS =  dbMetaData.getTables(catalog, "%", "%", new String[] { "TABLE" });
			ClassInfo classInfo = null;
			boolean importDdate = false;
			while (tableRS.next()) {
				String tableName = tableRS.getString("TABLE_NAME");
				log.info("tableName:{}", tableName);
				if (tableName.equals(contextConfig.getTableName())) {
					classInfo = new ClassInfo();
					classInfo.setTableName(tableName);
					log.info("表{}的注释:{}", tableName, tableRS.getString("REMARKS"));
					classInfo.setClassComment(tableRS.getString("REMARKS"));
					classInfo.setClassName(contextConfig.getEntityName());
					classInfo.setFullClassName(contextConfig.getBasePackage() + ".entity." + contextConfig.getEntityName());
					// 获取列的结果集
					ResultSet columnRS = dbMetaData.getColumns(catalog, "%", tableName, "%");

					List<Field> fieldList = new ArrayList<Field>();
					while (columnRS.next()) {
						String columnName = columnRS.getString("COLUMN_NAME");
						log.info("字段名称：{}", columnName);

						String columnType = columnRS.getString("TYPE_NAME").toUpperCase();
						log.info("字段类型：{}", columnType);

						String columnRemark = columnRS.getString("REMARKS");
						log.info("字段注释：{}", columnRemark);

						if (columnName == null || "".equals(columnName)) {
							continue;
						}

						Field ci = new Field();
						ci.setColumnName(columnName);
						ci.setFieldName(StringUtils.toCamelCase(columnName));
						ci.setFieldComment(columnRemark);
						ci.setFieldClass(StringUtils.dbType2Java(columnType));
						if (ci.getFieldClass().equals("Date")) {
							importDdate = true;
						}
						fieldList.add(ci);
					}
					classInfo.setFieldList(fieldList);
					classInfo.setPrimaryKey(primaryKeyColumnName(dbMetaData, tableName,catalog));
					classInfo.setConversionPrimaryKey(StringUtils.toCamelCase(classInfo.getPrimaryKey()));
					columnRS.close();
				}
			}
			if(classInfo ==null) {
				throw new RuntimeException("表不存在，請檢查配置");
			}
			GenaratorCtxBean genaratorCtxBean = new GenaratorCtxBean();
			EntityProcessBean entity = new EntityProcessBean(author, basePackage, classInfo);
			entity.setImportDdate(importDdate);
			genaratorCtxBean.setEntity(entity);
			genaratorCtxBean.setService(new ServiceProcessBean(author, basePackage, classInfo));
			genaratorCtxBean.setMapper(new MapperProcessBean(author, basePackage, classInfo));
			genaratorCtxBean.setMybatis(new MybatisProcessBean(author, basePackage, classInfo));
			genaratorCtxBean.setController(new ControllerProcessBean(author, basePackage, classInfo));
			tableRS.close();
			
			if (contextConfig.isModelFlag()) {
				EntityProcessBean entityProcessBean = genaratorCtxBean.getEntity();
				genFile(
						freemarkerTool,
						contextConfig,
						entityProcessBean.getClassInfo().getClassName().concat(".java"),
						"entity",
						genaratorCtxBean.getEntity());
			}
			if (contextConfig.isServiceFlag()) {
				EntityProcessBean entityProcessBean = genaratorCtxBean.getEntity();
				genFile(
						freemarkerTool,
						contextConfig,
						"I".concat(entityProcessBean.getClassInfo().getClassName()).concat("Service.java"),
						"service",
						genaratorCtxBean.getEntity());
			}
			if (contextConfig.isServiceImplFlag()) {
				EntityProcessBean entityProcessBean = genaratorCtxBean.getEntity();
				genFile(
						freemarkerTool,
						contextConfig,
						entityProcessBean.getClassInfo().getClassName().concat("ServiceImpl.java"),
						"service_impl",
						genaratorCtxBean.getEntity());
			}
			if (contextConfig.isMapperFlag()) {
				EntityProcessBean entityProcessBean = genaratorCtxBean.getEntity();
				genFile(
						freemarkerTool,
						contextConfig,
						entityProcessBean.getClassInfo().getClassName().concat("Mapper.java"),
						"mapper",
						genaratorCtxBean.getEntity());
			}
			if (contextConfig.isMapperXmlFlag()) {
				EntityProcessBean entityProcessBean = genaratorCtxBean.getEntity();
				genFile(
						freemarkerTool,
						contextConfig,
						entityProcessBean.getClassInfo().getClassName().concat("Mapper.xml"),
						"mybatis",
						genaratorCtxBean.getEntity());
			}
			if (contextConfig.isControlFlag()) {
				EntityProcessBean entityProcessBean = genaratorCtxBean.getEntity();
				genFile(
						freemarkerTool,
						contextConfig,
						entityProcessBean.getClassInfo().getClassName().concat("Controller.java"),
						"controller",
						genaratorCtxBean.getEntity());
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error("获取表、字段相关信息异常。。", e);
		} finally {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	private void genFile(FreemarkerTools freemarkerTools, ContextConfig contextConfig, String fileName, String modelType,
			GenaratorBaseBean genaratorCtxBean) throws FileNotFoundException, IOException, TemplateException {
		String diskPath=null;
		if(StringUtils.isBlank(contextConfig.getCodeDirPath())) {
			diskPath=System.getProperty("user.dir");
		}else {
			diskPath=contextConfig.getCodeDirPath().concat("/").concat(contextConfig.getProjectName());
		}
		String diskPackagePath = diskPath.concat("/").concat(contextConfig.getCodePath())
				.concat("/")
				.concat(contextConfig.getBasePackage().replaceAll("\\.", "/"));
		if("service_impl".equals(modelType)){
			diskPackagePath= diskPackagePath.concat("/service/impl");
		}else if("mybatis".equals(modelType)) {
			diskPackagePath= diskPath.concat("/").concat(contextConfig.getMapperPath());
		}else {
			diskPackagePath = diskPackagePath.concat("/").concat(modelType);
		}
		File file = new File(diskPackagePath, fileName);
		if (file.exists()) {
			file.delete();
		}else {
			 File dirFile = new File(diskPackagePath);
	         if (!dirFile.exists()) {
	                dirFile.mkdirs();
	          }
		}
		FileOutputStream outputStream = new FileOutputStream(file);
		String src = freemarkerTools.processString("xxl-code-generator/".concat(modelType).concat(".ftl"),
				genaratorCtxBean);
		outputStream.write(src.getBytes());
		outputStream.close();
		System.out.println(modelType + " generate success ... ");
	}

	private String primaryKeyColumnName(DatabaseMetaData dbMetaData, String tableName,String catalog) {
		try {
			ResultSet primaryKeyResultSet = dbMetaData.getPrimaryKeys(catalog, null, tableName);
			String primaryKeyColumnName =  "id";
			while (primaryKeyResultSet.next()) {
				primaryKeyColumnName = primaryKeyResultSet.getString("COLUMN_NAME");
			}
			return primaryKeyColumnName;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}
